module uart_byte_rx(
		clk,			   // 时钟发生器：system 50MHz
		rst_n, 			// 复位使能：reg
		uart_rx,		   // 串口接受线: system
		bps_setting, 	// 波特率：reg 
		check_setting, // 校验方式: reg
		
		
		data,			   // 数据: reg
		rx_done   		// 一次发送数据完成标志
	);
	
	input clk;
	input rst_n;
	input uart_rx;
	input [1:0]bps_setting;
	input [1:0]check_setting;
	
	output reg rx_done;
	output reg [7:0] data;
	
	reg en_baud_cnt;
	
	reg dff0_uart_rx;			// 第一级寄存输入uart
	reg dff1_uart_rx;			// 第二季寄存dff0
	reg pre_uart_rx; 			// 寄存uart信号，经过两级寄存，缓解了亚稳态问题
	wire nedge_uart_rx;		// 边沿检测条件
	
	wire w_rx_done;

	
	reg [15:0] div_cnt; 		// 分频计数器计数值
	reg [15:0] div_cnt_max; // 分频计数器最大值，在最大值时输出波特率信号
	reg bps_clk; 				// 波特率信号
	reg [3:0] bps_cnt;  		// 波特率时钟计数器
	reg [3:0] bps_cnt_max;  // 波特率时钟计数器最大值
	
	reg setting_en;
	reg check_switch; 		// 校验位开关
	reg check_type;	 		// 校验类型
	reg check_result_n;  	// 校验位
	reg [7:0] r_data;  		// 寄存的数据
	
	localparam START_BIT = 1'b0;
	localparam STOP_BIT = 1'b1;
	
	/**********************************************************************************
		uart 信号边沿检测逻辑，需要解决亚稳态 100MHz => 2级D触发器
	***********************************************************************************/
	
	always @(posedge clk)
		begin
			dff0_uart_rx <= uart_rx;
			dff1_uart_rx <= dff0_uart_rx;
			pre_uart_rx <= dff1_uart_rx;
		end
		
	assign nedge_uart_rx = (pre_uart_rx == 1) && (dff1_uart_rx == 0);
	
	
	/***********************************************************************************
		波特率使能信号
		当得到下降沿信号 nedge_uart_rx
	***********************************************************************************/
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		en_baud_cnt <= 1'b0;
	else if(nedge_uart_rx && div_cnt == 0)
		begin
			en_baud_cnt <= 1'b1;
			setting_en  <= 1'b1;
		end
	else if((div_cnt == div_cnt_max / 2) && (bps_cnt == 0) && (dff1_uart_rx == 1)) // 如果nedge_uart_rx是毛刺，取消使能
		en_baud_cnt <= 1'b0;
	else
		begin
			en_baud_cnt <= en_baud_cnt;
			setting_en  <= 1'b0;
		end
	
	/********************************************************************************
		波特率发生器
		当clk信号来临时，使能信号en_baud_cnt为1时，允许设置寄存器，开启波特率发生器
	 ********************************************************************************/
	// 寄存分频器设置
	always @(posedge clk or negedge rst_n)
	if (!rst_n)
		div_cnt_max <= 16'd5207;
	else if (setting_en)
		begin
			case(bps_setting)
				0:div_cnt_max <= 16'd434;    // 115200 bps
				1:div_cnt_max <= 16'd5207;   // 9600 bps 
				2:div_cnt_max <= 16'd10416;  // 4800 bps
				default:div_cnt_max <= 16'd434; // 默认是115200 bps	
			endcase
		end
	
	// 寄存校验位设置
	always @(posedge clk or negedge rst_n)
	if (!rst_n) 
		begin
			check_switch <= 1'b0;
			bps_cnt_max <=  4'd10;
		end
	else if (setting_en) 
		begin
			if (check_setting[1] == 1'b0) 
				begin
					check_switch 	<= 	1'b0;
					bps_cnt_max 	<=  	4'd10;
				end
			else 
				begin
					check_switch 	<= 	1'b1;
					check_type 		<=    check_setting[0];
					bps_cnt_max 	<= 	4'd11;
				end
		end
	else
		begin 
			check_switch 	<= 	check_switch;
			bps_cnt_max 	<= 	bps_cnt_max;
			check_type 		<= 	check_type;
		end 
	
	
	// 计数器，通过计数器来分频实现波特率发生器
	always @(posedge clk or negedge rst_n)
	if (!rst_n)
		div_cnt <= 16'b0;
	else if (en_baud_cnt) // 在发送期间需要开始计数
		begin
			if (div_cnt == div_cnt_max)
				div_cnt <= 16'b0;
			else 
				div_cnt <= div_cnt + 16'b1;
		end
	else						// 其他时候保持为0
		div_cnt <= 16'b0;
	
		
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		bps_clk 	<= 1'b0;
		else if (div_cnt == div_cnt_max)  // 只会有整个周期只会有一小段上升信号
		bps_clk 	<=	1'b1;
	else
		bps_clk 	<=	1'b0;
	
	
	/********************************************************************************
		位计数器，发送哪一位
	*********************************************************************************/
	always @(posedge clk or negedge rst_n)
	if (!rst_n)
		bps_cnt <= 4'd0;
	// 一旦bps_cnt == 7则将bps归0
	else if(bps_cnt == bps_cnt_max)
		bps_cnt <= 4'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;
	
	/*********************************************
		位接收逻辑
	**********************************************/
	always @(posedge clk or negedge rst_n)
	if (!rst_n)
		begin 
			check_result_n <= 1'b1;
			data <= 8'b0;
		end 
	else if (div_cnt == div_cnt_max / 2)  // 选择分频计数器计数中点中点采样
		begin
			case (bps_cnt)
				1: r_data[0] <= uart_rx;
				2: r_data[1] <= uart_rx;
				3: r_data[2] <= uart_rx;
				4: r_data[3] <= uart_rx;
				5: r_data[4] <= uart_rx;
				6: r_data[5] <= uart_rx;
				7: r_data[6] <= uart_rx;
				8: r_data[7] <= uart_rx;
				9:	begin // 是否采用奇偶校验，校验正确check_result_n 为0，错误为1
						if (check_switch)
								check_result_n <= (^r_data) ^ uart_rx ^ check_type;	
						else
							data <= r_data;
					end
				10: data <= r_data;
			default: data <= data;
		endcase
		end
	
	
	/*************************************************************************
		接收完成标志信号
	**************************************************************************/
	assign w_rx_done = (div_cnt == div_cnt_max) && (bps_cnt == bps_cnt_max - 1);
	always @(posedge clk)
		if(check_switch)
			rx_done <= w_rx_done && (!check_result_n);
		else 
			rx_done <= w_rx_done;
	
endmodule
